package com.smallkingson.ylib.view;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.PointF;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.Scroller;

import com.smallkingson.ylib.R;
import com.smallkingson.ylib.core.Yr;
import com.smallkingson.ylib.view.base.YView;
import com.smallkingson.ylib.view.utils.YCanvases;


public class YSwitch extends YView {

    private boolean isOn = false;

    private static final int DOWNRECT_IN = 0;

    private static final int DOWNRECT_OUT = 1;

    private int downRect;

    private PointF mRelativePoint;

    private int mBgWidth = LayoutParams.WRAP_CONTENT;

    private int mBgHeight = LayoutParams.WRAP_CONTENT;

    private int mFgWidth = LayoutParams.WRAP_CONTENT;

    private int mFgHeight = LayoutParams.WRAP_CONTENT;

    private Bitmap offBg;

    private Bitmap onBg;

    private Bitmap fg;

    private int xLast;

    private Rect fgRect;

    private Scroller mScroller;

    private float xDown;

    private int xDelta;

    private int duration = 200;

    private float total;

    private OnStateChangeListener onStateChangeListener;

    private int width;

    private int height;


    Runnable afterCreateTask;

    @SuppressLint("NewApi")
    public YSwitch(Context context, AttributeSet attrs) {

        super(context, attrs);

        mRelativePoint = new PointF();

        offBg = getBitmapByAttrs(R.styleable.yr_YSwitch_offBgRes);

        onBg = getBitmapByAttrs(R.styleable.yr_YSwitch_onBgRes);

        fg = getBitmapByAttrs(R.styleable.yr_YSwitch_fgRes);

        mBgHeight = (int) (mTypedArray.getDimension(
                R.styleable.yr_YSwitch_bgHeight, 40) + 0.5f);

        mBgWidth = (int) (mTypedArray.getDimension(
                R.styleable.yr_YSwitch_bgWidth, 100) + 0.5f);
        mFgWidth = (int) (mTypedArray.getDimension(
                R.styleable.yr_YSwitch_fgWidth, 46) + 0.5f);
        mFgHeight = (int) (mTypedArray.getDimension(
                R.styleable.yr_YSwitch_fgHeight, 60) + 0.5f);

        fgRect = new Rect();

        mScroller = new Scroller(context);

        setLayerType(View.LAYER_TYPE_HARDWARE, null);

    }

    public YSwitch(Context context) {
        super(context, null);
    }

    /**
     * 设置前景和背景的相差距离
     */
    public void setRelative(PointF point) {

        this.mRelativePoint = point;

        postInvalidate();
    }

    @SuppressLint("DrawAllocation")
    @Override
    protected void onDraw(Canvas canvas) {

        super.onDraw(canvas);

        // YCanvases.draw(canvas, bg, 0, 0, bg.getWidth(), bg.getHeight());

        float onBgAlpha = fgRect.left / total;

        canvas.save();

        canvas.translate(0, -fgRect.top);

        YCanvases.draw(canvas, onBg, 0, 0, mBgWidth, mBgHeight, onBgAlpha);

        YCanvases.draw(canvas, offBg, 0, 0, mBgWidth, mBgHeight, 1 - onBgAlpha);

        canvas.restore();

        YCanvases.draw(canvas, fg, (int) (fgRect.left + mRelativePoint.x), 0,
                fg.getWidth(), fg.getHeight());


    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
    }

    @Override
    public void computeScroll() {

        if (mScroller.computeScrollOffset()) {

            fgRect.set(mScroller.getCurrX(), fgRect.top, mScroller.getCurrX()
                    + mFgWidth, fgRect.bottom);

            postInvalidate();
        }

        super.computeScroll();
    }

    @Override
    protected void onCreate() {

        initRelative();

        initWidthAndHeight();

        scaleBitmap();

        initFgLocation();

        initTotal();
    }

    private void initRelative() {

        mRelativePoint.set(0, -1f);
    }

    private void initTotal() {

        total = getLayoutParams().width - mFgWidth;


    }

    private void initFgLocation() {

        this.fgRect.set((int) mRelativePoint.x, (int) mRelativePoint.y, mFgWidth,
                mFgHeight);
    }

    private void scaleBitmap() {

        if (mBgWidth != LayoutParams.WRAP_CONTENT
                && mBgHeight != LayoutParams.WRAP_CONTENT) {

            offBg = Bitmap.createScaledBitmap(offBg, mBgWidth, mBgHeight, true);

            onBg = Bitmap.createScaledBitmap(onBg, mBgWidth, mBgHeight, true);

        }
        if (mFgWidth != LayoutParams.WRAP_CONTENT
                && mFgHeight != LayoutParams.WRAP_CONTENT) {

            fg = Bitmap.createScaledBitmap(fg, mFgWidth, mFgHeight, true);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        getParent().requestDisallowInterceptTouchEvent(true);

        switch (event.getAction()) {

            case MotionEvent.ACTION_DOWN: {

                if (event.getX() < fgRect.left || event.getX() > fgRect.right
                        || event.getY() < fgRect.top || event.getY() > fgRect.bottom) {

                    downRect = DOWNRECT_OUT;
                } else {
                    downRect = DOWNRECT_IN;
                }
                xLast = fgRect.left;

                xDown = event.getX();

                return true;
            }
            case MotionEvent.ACTION_MOVE: {

                if (downRect == DOWNRECT_OUT) {
                    return true;
                }

                xDelta = (int) (event.getX() - xDown);

                // 更新前景位置

                int x = xDelta + xLast;

                if (x <= 0) {

                    fgRect.set(0, fgRect.top, mFgWidth, fgRect.bottom);

                } else if (x >= width - mFgWidth) {

                    fgRect.set(getWidth() - mFgWidth, fgRect.top, getWidth(),
                            fgRect.bottom);
                } else {

                    fgRect.set(x, fgRect.top, x + mFgWidth, fgRect.bottom);
                }

                postInvalidate();

                return true;
            }
            case MotionEvent.ACTION_UP: {

                if (xDelta == 0) {

                    toggle();

                } else {

                    startScroll();
                }

                xDelta = 0;

                break;
            }
        }

        return true;
    }

    public void toggle() {

        if (isOn) {

            setOff();

        } else {

            setOn();
        }
    }

    public void setOff() {

        if (width == 0) {

            initWidthAndHeight();
        }
        this.isOn = false;

        mScroller.startScroll(fgRect.left, 0, -fgRect.left, 0, duration);

        if (onStateChangeListener != null) {

            onStateChangeListener.onStateChange(this, false);
        }
        postInvalidate();
    }

    public boolean isOn() {

        return this.isOn;
    }

    public void setOn(final boolean isOn) {

        if (!isCreate) {

            postDelayed(new Runnable() {
                @Override
                public void run() {
                    setOn(isOn);
                }
            },50);
            return;
        }
        Yr.d(isOn);

        if (isOn) {
            setOn();
        } else {
            setOff();
        }
    }

    public void setOn() {

        if (width == 0) {

            initWidthAndHeight();
        }
        this.isOn = true;

        mScroller.startScroll(fgRect.left, 0, width - mFgWidth - fgRect.left, 0,
                duration);

        if (onStateChangeListener != null) {

            onStateChangeListener.onStateChange(this, this.isOn);
        }
        postInvalidate();
    }

    private void startScroll() {

        int location = fgRect.left + (fgRect.right - fgRect.left) / 2;

        if (location < mBgWidth / 2) {

            mScroller.startScroll(fgRect.left, 0, -fgRect.left, 0, duration);

            if (isOn && onStateChangeListener != null) {

                isOn = false;

                onStateChangeListener.onStateChange(this, isOn);
            }

        } else {

            mScroller.startScroll(fgRect.left, 0, getWidth() - mFgWidth
                    - fgRect.left, 0, duration);

            if (!isOn && onStateChangeListener != null) {

                isOn = true;

                onStateChangeListener.onStateChange(this, isOn);
            }
        }
        postInvalidate();

    }

    /*
     * --- *** ---
     */
    @SuppressLint("NewApi")
    private void initWidthAndHeight() {

        int maxWidth;

        int maxHeight;

        if (mBgWidth > mFgWidth) {

            maxWidth = mBgWidth;

            maxWidth += Math.abs(mRelativePoint.x);

        } else {

            maxWidth = mFgWidth;
        }
        if (mBgHeight > mFgHeight) {

            maxHeight = mBgHeight;

            maxHeight += Math.abs(mRelativePoint.y);

        } else {

            maxHeight = mFgHeight;
        }

        LayoutParams lp = this.getLayoutParams();

        lp.width = (int) Math.ceil(maxWidth + mRelativePoint.x);

        lp.height = maxHeight;

        width = lp.width;

        height = lp.height;

        this.setLayoutParams(lp);
    }

    public void setOnStateChangeListener(
            OnStateChangeListener onStateChangeListener) {

        this.onStateChangeListener = onStateChangeListener;
    }

    public static interface OnStateChangeListener {

        void onStateChange(View v, boolean isOn);
    }
}
